﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Collections;

using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Text.RegularExpressions;
using System.Web;

using System.Xml.Xsl;
using System.Xml.Schema;

using System.Diagnostics;
using System.Reflection;


namespace SchematronTestFramework
{
    class AssertMeta
    {
        public bool isInFirstRule;
        public bool isAssert;
        public XmlNode rule;
        public XmlNode pattern;
        public XmlNode assert;

        public string ruleContext;
        public string assertTest;

        public string errorText;

        public TestCommand command;
        
        public string generateSch()
        {
            string sch = "";
            if (isInFirstRule)
            {
                sch = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n" + "<schema xmlns = \"http://www.ascc.net/xml/schematron\"> \n <ns prefix = \"cda\" uri = \"urn:hl7-org:v3\"/>\n <ns prefix = \"ext\" uri = \"http://ns.electronichealth.net.au/Ci/Cda/Extensions/3.0\"/>\n <ns prefix = \"xs\" uri = \"http://www.w3.org/2001/XMLSchema\"/>\n <ns prefix = \"xsi\" uri = \"http://www.w3.org/2001/XMLSchema-instance\"/>\n" + "    \n<pattern name=\"test\">\n";
                sch = sch + "<rule context=\"" + ruleContext + "\">\n";
                sch = sch + assert.OuterXml + "\n";

                sch = sch + "</rule>\n" + "</pattern>\n" + "</schema>\n";
            }
            else
            {
                XmlNode firstRule = null;
                XmlNodeList rules = pattern.ChildNodes;
                foreach (XmlNode n in rules)
                {
                    if (n != null && n.Name.CompareTo("rule") == 0)
                    {
                        firstRule = n;
                        break;
                    }
                }
                if (firstRule != null && firstRule.Name.CompareTo("rule") == 0)
                {
                    XmlAttributeCollection atts = firstRule.Attributes;

                    string context = "";
                    if (atts != null)
                    {
                        foreach (XmlAttribute attr in atts)
                        {
                            if (attr != null && attr.Name.CompareTo("context") == 0)
                            {
                                context = attr.Value;
                                break;
                            }
                        }
                    }
                    if (context.Length > 0)
                    {
                        string rule = "<rule context=\"" + context + "\">\n</rule>\n";
                        sch = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n" + "<schema xmlns = \"http://www.ascc.net/xml/schematron\"> \n <ns prefix = \"cda\" uri = \"urn:hl7-org:v3\"/>\n <ns prefix = \"ext\" uri = \"http://ns.electronichealth.net.au/Ci/Cda/Extensions/3.0\"/>\n <ns prefix = \"xs\" uri = \"http://www.w3.org/2001/XMLSchema\"/>\n <ns prefix = \"xsi\" uri = \"http://www.w3.org/2001/XMLSchema-instance\"/>\n" + "    \n<pattern name=\"test\">\n";
                        sch = sch + rule;
                        sch = sch + "<rule context=\"" + ruleContext + "\">\n";
                        sch = sch + assert.OuterXml + "\n";

                        sch = sch + "</rule>\n" + "</pattern>\n" + "</schema>\n";
                    }
                }
            }
            //sch = Regex.Replace(sch, @"xsi:", "xsi", RegexOptions.IgnoreCase);
            return sch;
        }

        public void run(string file,string report,string schematron)
        {
            Reporter reporter = new Reporter(report);
            string sch = generateSch();

            if (Regex.Match(errorText, @"(?s)(?i)'.*'\s*tag\s*is\s*missing").Value.Length > 0)
            {
                command = new NodeExistenceTest(file, ruleContext, assertTest, assertTest, errorText, sch,report,schematron);
                command.run();
            }
            else if (Regex.Match(errorText, @"(?s)(?i).*more\s*tags\s*are\s*missing").Value.Length > 0)
            {
                command = new FullPathTest(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.run();
            }
            else if (Regex.Match(errorText, @"(?s)(?i)'.*'\s*tag\s*shall\s*appear").Value.Length > 0)
            {
                command = new NodeNumberTest(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.run();
            }
            else if (Regex.Match(errorText, @"(?s)(?i)'.*'\s*tag\s*shall\s*contain.*value").Value.Length > 0)
            {
                command = new NodeValueTest(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.run();
            }
            else if (Regex.Match(errorText, @"(?s)(?i)tag\s*'.*'\s*attribute\s*is\s*missing").Value.Length > 0)
            {
                command = new AttributeExistenceTest(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.run();
            }
            else if (Regex.Match(errorText, @"(?s)(?i)'.*'\s*attribute\s*shall\s*appear\s*once").Value.Length > 0)
            {
                command = new AttributeNumberTest(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.run();
            }
            else if (Regex.Match(errorText, @"(?s)(?i)'.*'\s*attribute\s*shall\s*contain").Value.Length > 0)
            {
                command = new AttributeEmptyTest(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.run();
            }
            else if (Regex.Match(errorText, @"(?s)(?i)'.*'\s*attribute\s*shall\s*be").Value.Length > 0)
            {
                command = new AttributeValueTest(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.run();
            }

            else
            {

                
                TestCommand.notrun++;
                command = new TestCommand(file, ruleContext, assertTest, assertTest, errorText, sch, report, schematron);
                command.result = "notrun";

                Console.WriteLine("========== NOT RUN  ---  Something Wrong in the Error Text =============\n" +
                    "File: " + schematron + "\n" +
                    "Line: " + command.getLineNumber(errorText) + "\n" +
                    "************************************************************************\n\n"
                    );
                System.IO.Directory.Delete(command.workingfolder, true);
                //command = new TestCommand(file, ruleContext, assertTest, assertTest, errorText, sch);
                //command.run();
            }

            if (command.result.CompareTo("passed") == 0)
            {
                //reporter.CreateMessage(schematron, command.getLineNumber(errorText), "Passed", assertTest);
            }
            else if (command.result.CompareTo("falsenegative") == 0)
            {
                reporter.CreateMessage(schematron, command.getLineNumber(errorText), "False Negative", assertTest);
            }
            else if (command.result.CompareTo("error") == 0)
            {
                reporter.CreateMessage(schematron, command.getLineNumber(errorText), "Error", assertTest);
            }
            else if (command.result.CompareTo("notrun") == 0)
            {
                reporter.CreateMessage(schematron, command.getLineNumber(errorText), "Not Run", assertTest);
            }
        }
        public AssertMeta(XmlNode pat, XmlNode rul, XmlNode ass)
        {
            pattern = pat;
            rule = rul;
            assert = ass;
            //reporter.GenerateXmlReport();
            XmlNode firstchild = null;
            XmlNodeList rules = pattern.ChildNodes;
            foreach (XmlNode n in rules)
            {
                if (n != null && n.Name.CompareTo("rule") == 0)
                {
                    firstchild = n;
                    break;
                }
            }

            if (firstchild != null)
            {
                isInFirstRule = firstchild.Equals(rule);
            }
            else
            {
                isInFirstRule = false;
            }
            if (rule != null)
            {
                XmlAttributeCollection atts = rule.Attributes;
                foreach (XmlAttribute attr in atts)
                {
                    if (attr.Name.CompareTo("context") == 0)
                    {
                        ruleContext = attr.Value;
                        break;
                    }
                }
            }
            if (assert != null)
            {

                if (assert.Name.CompareTo("assert") == 0)
                {
                    isAssert = true;

                }
                else
                {
                    isAssert = false;
                }

                XmlAttributeCollection atts_t = assert.Attributes;
                foreach (XmlAttribute att_t in atts_t)
                {
                    if (att_t.Name.CompareTo("test") == 0)
                    {
                        assertTest = att_t.Value;
                    }
                }
                errorText = assert.InnerText;
            }
            else
            {
                isAssert = false;
            }


        }

    }
}
